package cc.rengu.igas.cops.core.service.trans.payment;
import cc.rengu.igas.cops.common.enums.RespCodeEnum;
import cc.rengu.igas.cops.core.service.base.ManageService;
import cc.rengu.igas.cops.facade.bean.OrderDetail;
import cc.rengu.igas.cops.facade.request.PayConfirmRequest;
import cc.rengu.igas.cops.facade.response.PayConfirmResponse;
import cc.rengu.igas.share.common.constant.TransCacheConstant;
import cc.rengu.igas.share.common.enums.FeeTypeEnum;
import cc.rengu.igas.share.core.model.TransLimitBean;
import cc.rengu.igas.share.core.realize.BompService;
import cc.rengu.igas.share.core.realize.MchntService;
import cc.rengu.igas.share.core.realize.impl.BompServiceImpl;
import cc.rengu.igas.share.core.realize.impl.MchntServiceImpl;
import cc.rengu.oltp.service.base.ChannelBaseService;
import cc.rengu.oltp.service.common.constant.AppParamConstant;
import cc.rengu.oltp.service.common.constant.TreeNodeConstant;
import cc.rengu.oltp.service.common.dao.MchntOrderDetailMapper;
import cc.rengu.oltp.service.common.dao.MchntOrderInfoMapper;
import cc.rengu.oltp.service.common.dao.PayOrderInfoMapper;
import cc.rengu.oltp.service.common.dao.UserOrderInfoMapper;
import cc.rengu.oltp.service.common.dao.impl.MchntOrderDetailMapperImpl;
import cc.rengu.oltp.service.common.dao.impl.MchntOrderInfoMapperImpl;
import cc.rengu.oltp.service.common.dao.impl.PayOrderInfoMapperImpl;
import cc.rengu.oltp.service.common.dao.impl.UserOrderInfoMapperImpl;
import cc.rengu.oltp.service.common.entity.*;
import cc.rengu.oltp.service.common.enums.*;
import cc.rengu.oltp.service.model.BizException;
import cc.rengu.oltp.service.model.BizResponse;
import cc.rengu.oltp.service.model.OrderInfo;
import cc.rengu.oltp.service.model.TransLimitInfo;
import cc.rengu.oltp.service.realize.OrderService;
import cc.rengu.oltp.service.realize.TransCustomImpl;
import cc.rengu.oltp.service.realize.TransLimitService;
import cc.rengu.oltp.service.realize.impl.OrderServiceImpl;
import cc.rengu.oltp.service.realize.impl.TransLimitServiceImpl;
import cc.rengu.oltp.utility.util.*;
import com.alibaba.fastjson.JSON;

import java.util.*;
import java.util.stream.Collectors;

/**
 * 担保支付确认
 * Created by LS on 2020/8/14.
 */
public class CopsPayConfirmService extends ManageService implements TransCustomImpl {
    @Override
    protected Object bizBeforeCust() throws Exception {
        PayConfirmRequest payConfirmRequest = new PayConfirmRequest();
        ConvertUtil.convertOutput(payConfirmRequest);
        return payConfirmRequest;
    }

    @Override
    protected BizResponse bizProcessCust(Object request) throws Exception {
        PayConfirmRequest payConfirmRequest = (PayConfirmRequest) request;
        String instId = payConfirmRequest.getHeader().getInstId();
        String userOrderId = payConfirmRequest.getUserOrderId();
        String totalComfirmAmt = payConfirmRequest.getOrderAmt();
        List<OrderDetail> confirmOrderDetailList = payConfirmRequest.getConfirmOrderDetailList();

        /* Step1：请求参数业务规则校验 */
        if (StringUtil.isEmptyOrNull(totalComfirmAmt) || StringUtil.isEmptyOrNull(userOrderId) ||
                null == confirmOrderDetailList || confirmOrderDetailList.isEmpty()){
            rglog.error("请求参数不合法,orderAmt:{},userOrderId:{},confirmOrderDetailList:{}",totalComfirmAmt,userOrderId,JSON.toJSONString(confirmOrderDetailList));
            throw new BizException(RespCodeEnum.MSG_VALID_CHECK_ERROR.getRespCode(),RespCodeEnum.MSG_VALID_CHECK_ERROR.getRespDesc());
        }else {
            String countComfirmAmt = "0.00";
            for (OrderDetail orderDetail : confirmOrderDetailList){
                countComfirmAmt = AmountUtil.addition(countComfirmAmt,orderDetail.getOrderAmt());
            }
            if (AmountUtil.compare(totalComfirmAmt, countComfirmAmt) != 0) {
                rglog.info("订单明细金额之和:<{}>与确认收款总额:<{}>不一致", countComfirmAmt, totalComfirmAmt);
                throw new BizException(RespCodeEnum.PARAM_ERROR.getRespCode(), RespCodeEnum.PARAM_ERROR.getRespDesc());
            }
            /* Step1.1：校验确认收货是否存在上送多个商户，确认收货只支持单个商户多个子订单的确认收货 */
            Set<String> mchntNoSet = new HashSet<>();
            confirmOrderDetailList.forEach(item -> mchntNoSet.add(item.getMchntNo()));
            if (mchntNoSet.size() > 1){
                rglog.error("确认收货只支持单个商户的多个子订单进行确认收货，不支持多个商户的确认收货!");
                throw new BizException(RespCodeEnum.ORDER_CANT_CONFIRM.getRespCode(),RespCodeEnum.ORDER_CANT_CONFIRM.getRespDesc());
            }
            /* Step1.2：控制确认收货并发场景 */
            for (OrderDetail orderDetail : confirmOrderDetailList){
                String hashKey = orderDetail.getMchntNo() + userOrderId + orderDetail.getMchntSubOrderId();
                String confirmFlag = RedisUtil.hashGet(AppParamConstant.TRANS_CTRL_CACHE,hashKey);
                if (!StringUtil.isEmptyOrNull(confirmFlag) && AppParamConstant.YES.equals(confirmFlag)){
                    rglog.error("当前商户子订单正在进行确认收货，不允许重复发起，请稍后重试!");
                    throw new BizException(RespCodeEnum.ORDER_CANT_CONFIRM.getRespCode(),RespCodeEnum.ORDER_CANT_CONFIRM.getRespDesc());
                }
                RedisUtil.hashSet(AppParamConstant.TRANS_CTRL_CACHE,hashKey,"3");
            }
        }

        /* Step2：获取用户订单信息 */
        UserOrderInfoMapper userOrderInfoMapper = new UserOrderInfoMapperImpl();
        UserOrderInfo userOrderInfo = userOrderInfoMapper.selectUserOrderInfoByUserOrderId(instId, userOrderId);
        if (null == userOrderInfo) {
            rglog.info("用户支付订单不存在");
            throw new BizException(RespCodeEnum.ORDER_NOEXIT.getRespCode(), RespCodeEnum.ORDER_NOEXIT.getRespDesc());
        }else if (!OrderStatusEnum.FINISH.getStatus().equals(userOrderInfo.getOrderStatus())
                || !TransStatusEnum.TRANS_SUCC.getStatus().equals(userOrderInfo.getTransStatus())
                || BizStatusEnum.REFUND.getStatus().equals(userOrderInfo.getBizStatus())
                || BizStatusEnum.NOT_CONFIRM_REFUND.getStatus().equals(userOrderInfo.getBizStatus())) {
            rglog.warn("该支付订单未支付成功或已经全额退款,订单状态:<{}>,交易状态:<{}>,业务状态:<{}>,拒绝交易!",
                    userOrderInfo.getOrderStatus(), userOrderInfo.getTransStatus(), userOrderInfo.getBizStatus());
            throw new BizException(RespCodeEnum.ORDER_CANT_CONFIRM.getRespCode(), RespCodeEnum.ORDER_CANT_CONFIRM.getRespDesc());
        }

        /* Step3：获取支付订单信息 */
        PayOrderInfoMapper payOrderInfoMapper = new PayOrderInfoMapperImpl();
        List<PayOrderInfo> payOrderInfoList = payOrderInfoMapper.selectPayOrderInfoBySysSeqNum(userOrderInfo.getInstId(), userOrderInfo.getSysSeqNum());
        if (null == payOrderInfoList || payOrderInfoList.isEmpty()) {
            rglog.info("支付订单表不存在该笔订单，instId:<{}>,sysSeqNum:<{}>", userOrderInfo.getInstId(), userOrderInfo.getSysSeqNum());
            throw new BizException(RespCodeEnum.ORDER_NOEXIT.getRespCode(), RespCodeEnum.ORDER_NOEXIT.getRespDesc());
        }
        payOrderInfoList = payOrderInfoList.stream().filter(item -> !ChannelEnum.ACCT.getChannelType().equals(item.getMsgDstId()) &&
                !ChannelEnum.MOMP.getChannelType().equals(item.getMsgDstId())).collect(Collectors.toList());
        if (payOrderInfoList.isEmpty()) {
            rglog.info("支付订单表中不存在有主支付方式的订单:<{}>", JSON.toJSONString(payOrderInfoList));
            throw new BizException(RespCodeEnum.ORDER_NOEXIT.getRespCode(), RespCodeEnum.ORDER_NOEXIT.getRespDesc());
        }
        PayOrderInfo payOrderInfo = payOrderInfoList.get(0);
        GlobalTransUtil.setCacheValue(TransCacheConstant.PAY_ORDER_INFO,payOrderInfo);

        /* Step4：获取商户订单信息 */
        OrderServiceImpl orderService = new OrderServiceImpl();
        MchntOrderInfo mchntOrderInfo = checkMchntOrderInfo(userOrderInfo, payConfirmRequest);
        /* Step4.1：生成确认收货订单信息 */
        MchntOrderInfo confirmMchntOrderInfo = generateConfirmMchntOrderInfo(mchntOrderInfo,payConfirmRequest);
        UserOrderInfo confirmUserOrderInfo = new UserOrderInfo();
        BeanUtil.beanCopy(confirmMchntOrderInfo,confirmUserOrderInfo);
        confirmUserOrderInfo.setMsgSrcId(payConfirmRequest.getHeader().getSrcSysId());
        confirmUserOrderInfo.setTransChannelId(payConfirmRequest.getHeader().getChanlId());
        confirmUserOrderInfo.setGroupMchntNo(payConfirmRequest.getPlatMchntNo());
        confirmUserOrderInfo.setFrontSeqNum(payConfirmRequest.getHeader().getTraceNo());
        confirmUserOrderInfo.setTxnNum(confirmMchntOrderInfo.getTxnNum());
        confirmUserOrderInfo.setRealPayAmt(confirmUserOrderInfo.getOrderAmt());
        confirmUserOrderInfo.setNeedPayAmt(confirmUserOrderInfo.getOrderAmt());
        confirmUserOrderInfo.setOrderCreateTime(DateUtil.getCurrentDateTime("yyyyMMddHHmmss"));
        confirmUserOrderInfo.setOrderExpiryTime(confirmUserOrderInfo.getOrderCreateTime());
        confirmUserOrderInfo.setOrderStatus(OrderStatusEnum.FINISH.getStatus());
        if (!orderService.registerOrderInfo(confirmUserOrderInfo, Collections.singletonList(confirmMchntOrderInfo), null)) {
            rglog.error("登记确认收货的商户订单表失败");
            throw new BizException(RespCodeEnum.INSERT_PAY_ORDER_ERROR.getRespCode(), RespCodeEnum.INSERT_PAY_ORDER_ERROR.getRespDesc());
        }
        /* Step4.2：更新订单状态为已确认收货 */
        userOrderInfo.setBizStatus(BizStatusEnum.CONFIRM.getStatus());
        mchntOrderInfo.setBizStatus(BizStatusEnum.CONFIRM.getStatus());
        payOrderInfo.setBizStatus(BizStatusEnum.CONFIRM.getStatus());
        if (!orderService.updateOrderInfo(userOrderInfo, Collections.singletonList(mchntOrderInfo), payOrderInfo)) {
            rglog.info("更新用户订单/商户订单/支付订单为确认收货状态失败");
            throw new BizException(RespCodeEnum.UPDATE_ORDER_ERROR.getRespCode(), RespCodeEnum.UPDATE_ORDER_ERROR.getRespDesc());
        }
        /* Step4.3：更新商户子订单为确认收货 */
        updateMchntOrderDetails(payConfirmRequest, mchntOrderInfo);

        /* Step5：更新商户累计限额：先调用商户限额检查获取限额配置(账户类型为空则不进行限制检查) */
        MchntService mchntService = new MchntServiceImpl();
        List<TransLimitInfo> transLimitInfoList = mchntService.getMchntTransLimitInfo(instId, confirmMchntOrderInfo.getMchntNo(), null,null);
        if (null != transLimitInfoList && !transLimitInfoList.isEmpty()) {
            TransLimitBean transLimitBean = new TransLimitBean();
            transLimitBean.setLimitInst(confirmMchntOrderInfo.getMchntNo());
            transLimitBean.setOrderAmt(confirmMchntOrderInfo.getOrderAmt());
            transLimitBean.setTransLimitInfoList(transLimitInfoList);
            GlobalTransUtil.setCacheValue(TransCacheConstant.MCHNT_TRANS_LIMIT_INFO_LIST, transLimitBean);
            confirmMchntOrderInfo.setBizSceneType(null);
            mchntService.updateMchntTransLimit(confirmMchntOrderInfo);
        }

        /* Step6：通道服务调用 */
        if (null == txnInfo.getChannelCallCfgList() || txnInfo.getChannelCallCfgList().isEmpty()) {
            rglog.error("<{}-{}>交易未配置交易通道服务调用配置信息！", txnInfo.getSrcTxnAuthCfg().getTxnNum(), txnInfo.getSrcTxnAuthCfg().getTxnName());
            throw new BizException(RespCodeEnum.CHANNEL_CONFIG_NOT_EXIST.getRespCode(), RespCodeEnum.CHANNEL_CONFIG_NOT_EXIST.getRespDesc());
        }
        List<ChannelCallCfg> channelCallCfgList = txnInfo.getChannelCallCfgList().stream().filter(item ->
                item.getCallIndex().equals(ChannelBaseService.FIRST_CHANNEL_CALL_INDEX)).collect(Collectors.toList());
        ChannelCallCfg channelCallCfg = channelCallSceneDiscern(payConfirmRequest, channelCallCfgList);
        Class channelClasz = Class.forName(channelCallCfg.getCallChannelImpl());
        ChannelBaseService channelBaseService = (ChannelBaseService) channelClasz.newInstance();
        OrderInfo orderInfo = new OrderInfo();
        orderInfo.setUserOrderInfo(confirmUserOrderInfo);
        orderInfo.setMchntOrderInfoList(Collections.singletonList(mchntOrderInfo));
        channelBaseService.callService(txnInfo, orderInfo, channelCallCfg.getBizScene(), request);

        /* Step7：组装应答报文 */
        BizResponse<PayConfirmResponse> bizResponse = new BizResponse<>();
        bizResponse.setRspSysId(AppParamConstant.IGAS);
        bizResponse.setRespCode(RespCodeEnum.TRANS_SUCCESS.getRespCode());
        bizResponse.setRespDesc(RespCodeEnum.TRANS_SUCCESS.getRespDesc());
        return bizResponse;
    }

    @Override
    protected void bizAfterCust(Object response) throws Exception {
        BizResponse bizResponse = (BizResponse) response;
        PayConfirmResponse payConfirmResponse = (PayConfirmResponse) bizResponse.getResult();
        ConvertUtil.convertInput(payConfirmResponse);
    }

    @Override
    public ChannelCallCfg channelCallSceneDiscern(Object request, List<ChannelCallCfg> channelCallCfgList) throws Exception {
        String bizSceneType = (String) GlobalTransUtil.getCacheValue(TransCacheConstant.BIZ_SCENE_TYPE);
        if (!StringUtil.isEmptyOrNull(bizSceneType) && ("00".equals(bizSceneType) || "02".equals(bizSceneType))){
            /* 卡卷核销场景 */
            Optional<ChannelCallCfg> channelCallCfgOpt = channelCallCfgList.stream().filter(item -> item.getBizScene().equals("01")).findFirst();
            return channelCallCfgOpt.orElse(null);
        }else {
            /* 担保支付场景 */
            Optional<ChannelCallCfg> channelCallCfgOpt = channelCallCfgList.stream().filter(item -> item.getBizScene().equals("00")).findFirst();
            return channelCallCfgOpt.orElse(null);
        }
    }

    @Override
    public CheckResultEnum channelCallPreCheck(Object request, ChannelCallCfg channelCallCfg, OrderInfo orderInfo) throws Exception {
        if (ChannelEnum.MOMP.getChannelType().equals(channelCallCfg.getCallChannelId())) {
            String bizSceneType = (String) GlobalTransUtil.getCacheValue(TransCacheConstant.BIZ_SCENE_TYPE);
            MchntOrderInfo mchntOrderInfo = orderInfo.getMchntOrderInfoList().get(0);
            PayOrderInfo payOrderInfo = (PayOrderInfo) GlobalTransUtil.getCacheValue(TransCacheConstant.PAY_ORDER_INFO);
            if (!StringUtil.isEmptyOrNull(bizSceneType) && ("00".equals(bizSceneType) || "02".equals(bizSceneType)) && null != mchntOrderInfo &&
                    null != payOrderInfo && (StringUtil.isEmptyOrNull(mchntOrderInfo.getMchntFee()) || AmountUtil.compare("0", mchntOrderInfo.getMchntFee()) == 0)) {
                MchntService mchntService = new MchntServiceImpl();
                boolean calcResult = mchntService.calcMchntFee(mchntOrderInfo, convFeeType(payOrderInfo));
                if (!calcResult) {
                    rglog.error("卡卷核销场景计算商户手续费失败！");
                    return CheckResultEnum.REFUSE;
                }
            }
        }
        return CheckResultEnum.PASSED;
    }

    @Override
    public TransStatusEnum channelCallResultProc(Object request, ChannelCallCfg channelCallCfg, TransStatusEnum transStatusEnum, Object channelResponse, OrderInfo needUpdateOrderInfo) throws Exception {
        return transStatusEnum;
    }


    /**
     * 检查商户订单/判断商户订单是否是担保支付/判断确认收货的子订单是否完成确认收货
     *
     * @param userOrderInfo 用户订单
     * @param payConfirmRequest 请求体
     * @return  商户订单信息
     * @throws Exception 异常
     */
    private MchntOrderInfo checkMchntOrderInfo(UserOrderInfo userOrderInfo, PayConfirmRequest payConfirmRequest) throws Exception {
        XmlTreeUtil xmlTreeUtil = new XmlTreeUtil();
        String instId = payConfirmRequest.getHeader().getInstId();
        List<OrderDetail> confirmOrderDetailList = payConfirmRequest.getConfirmOrderDetailList();

        /* Step1：获取商户订单信息 */
        MchntOrderInfoMapper mchntOrderInfoMapper = new MchntOrderInfoMapperImpl();
        List<MchntOrderInfo> mchntOrderInfoList = mchntOrderInfoMapper.selectMchntOrderInfoBySysSeqNum(userOrderInfo.getInstId(), userOrderInfo.getSysSeqNum());
        if (null == mchntOrderInfoList || mchntOrderInfoList.isEmpty()) {
            rglog.warn("商户订单信息表中无该笔订单,instId:<{}>,sysSeqNum:<{}>", userOrderInfo.getInstId(), userOrderInfo.getSysSeqNum());
            throw new BizException(RespCodeEnum.ORDER_NOEXIT.getRespCode(), RespCodeEnum.ORDER_NOEXIT.getRespDesc());
        }
        /* Step1.1：对商户订单信息进行过滤，只保留当前确认收货的商户订单信息 */
        mchntOrderInfoList = mchntOrderInfoList.stream().filter(item -> item.getMchntNo().equals(confirmOrderDetailList.get(0).getMchntNo())).collect(Collectors.toList());
        if (mchntOrderInfoList.size() != 1){
            rglog.info("商户订单不存或者当前确认收货的商户订单异常:{}",JSON.toJSONString(mchntOrderInfoList));
            throw new BizException(RespCodeEnum.ORDER_NOEXIT.getRespCode(), RespCodeEnum.ORDER_NOEXIT.getRespDesc());
        }
        MchntOrderInfo mchntOrderInfo = mchntOrderInfoList.get(0);
        String transStatus = mchntOrderInfo.getTransStatus();
        String bizSceneType = mchntOrderInfo.getBizSceneType();
        String mchntOrderId = mchntOrderInfo.getMchntOrderId();

        /* Step2：判断订单状态且商户订单必须是担保支付的订单或购买卡券的订单 */
        if (!transStatus.equals(TransStatusEnum.TRANS_SUCC.getStatus())) {
            rglog.info("商户订单未支付成功，拒绝交易:{}", JSON.toJSONString(mchntOrderInfo));
            throw new BizException(RespCodeEnum.TRANS_IN_PROGRESS.getRespCode(), RespCodeEnum.ORDER_NOEXIT.getRespDesc());
        } else if (StringUtil.isEmptyOrNull(bizSceneType)) {
            rglog.warn("当前交易非担保支付交易或购买卡券的交易:{}", JSON.toJSONString(mchntOrderInfo));
            throw new BizException(RespCodeEnum.NOT_SURP_TRANS_TYPE_ERROR.getRespCode(), RespCodeEnum.NOT_SURP_TRANS_TYPE_ERROR.getRespDesc());
        }

        /* Step3：获取当前确认收货的订单,判断订单是否已经确认收货 */
        MchntOrderDetailMapper mchntOrderDetailMapper = new MchntOrderDetailMapperImpl();
        List<MchntOrderDetail> mchntOrderDetailList = new ArrayList<>();
        String redeemCouponIds = "";
        String orderDiscountAmt = "";
        String orderSettleAmt = "";
        for (OrderDetail orderDetail : confirmOrderDetailList) {
            /* Step3.1：获取商户子订单信息 */
            MchntOrderDetail mchntOrderDetail = mchntOrderDetailMapper.selectMchntOrderDetailByPrimaryKey(instId, orderDetail.getMchntNo(), mchntOrderId, orderDetail.getMchntSubOrderId());
            if (null == mchntOrderDetail) {
                rglog.info("子订单不存在");
                throw new BizException(RespCodeEnum.ORDER_NOEXIT.getRespCode(), RespCodeEnum.ORDER_NOEXIT.getRespDesc());
            }
            /* Step3.2：判断订单是否已经完成确认收货 */
            if ("00".equals(mchntOrderDetail.getMchntOrderStatus())) {
                rglog.info("当前商户子订单已经完成确认收货或卡券核销，subMchntOrderStatus:<{}>", mchntOrderDetail.getMchntOrderStatus());
                throw new BizException(RespCodeEnum.ORDER_ALREADY_CONFIRM.getRespCode(), RespCodeEnum.ORDER_ALREADY_CONFIRM.getRespDesc());
            }
            /* Step3.3：校验当前确认收货金额 + 子订单已经退款金额 = 子订单订单金额 */
            String addAmt = AmountUtil.addition(orderDetail.getOrderAmt(), mchntOrderDetail.getRefundAmt());
            rglog.info("当前子订单确认收货金额:<{}>,该子订单累计退款金额:<{}>,子订单订单金额:<{}>",
                    orderDetail.getOrderAmt(), mchntOrderDetail.getRefundAmt(), mchntOrderDetail.getOrderAmt());
            if (AmountUtil.compare(addAmt, mchntOrderDetail.getOrderAmt()) != 0) {
                rglog.info("子订单确认收货金额+累计退款金额不等于子订单订单金额...");
                throw new BizException(RespCodeEnum.ORDER_CANT_CONFIRM.getRespCode(), RespCodeEnum.ORDER_CANT_CONFIRM.getRespDesc());
            }
            mchntOrderDetailList.add(mchntOrderDetail);
            /* Step3.4：记录待核销卡券的卡券编号 */
            if ("00".equals(bizSceneType) || "01".equals(bizSceneType)) {
                redeemCouponIds = orderDetail.getMchntSubOrderId() + ",";
            }
            orderDiscountAmt = AmountUtil.addition(orderDiscountAmt, orderDetail.getOrderDiscountAmt());
            orderSettleAmt = AmountUtil.addition(orderSettleAmt, orderDetail.getOrderSettleAmt());
        }
        xmlTreeUtil.setXmlTreeStringValue("orderDiscountAmt", orderDiscountAmt);
        xmlTreeUtil.setXmlTreeStringValue("orderSettleAmt", orderSettleAmt);

        /* Step4：将确认收货的商户子订单及核销卡卷信息放到交易缓存中 */
        GlobalTransUtil.setCacheValue(TransCacheConstant.BIZ_SCENE_TYPE,bizSceneType);
        GlobalTransUtil.setCacheValue(TransCacheConstant.COUPON_ID_LIST,redeemCouponIds);
        GlobalTransUtil.setCacheValue(TransCacheConstant.MCHNT_ORDER_INFO,mchntOrderInfo);
        GlobalTransUtil.setCacheValue(TransCacheConstant.MCHNT_ORDER_DETAIL_LIST,mchntOrderDetailList);
        return mchntOrderInfo;
    }

    /**
     * 生成确认收货/卡券核销的商户订单
     *
     * @param mchntOrderInfo 原商户订单信息
     * @param payConfirmRequest 请求体
     * @return 确认收货的商户订单
     * @throws Exception 异常
     */
    private MchntOrderInfo generateConfirmMchntOrderInfo(MchntOrderInfo mchntOrderInfo, PayConfirmRequest payConfirmRequest) throws Exception {
        XmlTreeUtil xmlTreeUtil = new XmlTreeUtil();
        String instId = payConfirmRequest.getHeader().getInstId();
        String mchntNo = mchntOrderInfo.getMchntNo();
        String origSysSeqNum = mchntOrderInfo.getSysSeqNum();

        /* Step1：获取已退款或者确认收货的商户订单信息 */
        MchntOrderInfoMapper mchntOrderInfoMapper = new MchntOrderInfoMapperImpl();
        List<MchntOrderInfo> refundOrComfirmMchntOrderInfos = mchntOrderInfoMapper.selectMchntOrderInfoByOrigSysSeqNum(instId, origSysSeqNum);
        /* Step1.1：获取已确认的商户订单计算已经确认收货的订单金额 */
        String comfirmedMchntOrderAmt = "0.00";
        String comfirmCtomerMarketAmt = "0.00";
        String realSettleAmt = "0.00";
        String mchntSettleAmt = "0.00";
        String mchntFee = "0.00";
        String realMchntFee = "0.00";
        if (refundOrComfirmMchntOrderInfos != null && !refundOrComfirmMchntOrderInfos.isEmpty()) {
            List<MchntOrderInfo> comfirmMchntOrderList = refundOrComfirmMchntOrderInfos.stream().filter(item -> "P05CP001".equals(item.getTxnNum())
                    && mchntNo.equals(item.getMchntNo())).collect(Collectors.toList());
            for (MchntOrderInfo comfirmMchntOrderInfo : comfirmMchntOrderList) {
                comfirmedMchntOrderAmt = AmountUtil.addition(comfirmedMchntOrderAmt, comfirmMchntOrderInfo.getOrderAmt());
                comfirmCtomerMarketAmt = AmountUtil.addition(comfirmCtomerMarketAmt, comfirmMchntOrderInfo.getCustomerMarketAmt());
                realSettleAmt = AmountUtil.addition(realSettleAmt, comfirmMchntOrderInfo.getRealSettleAmt());
                mchntSettleAmt = AmountUtil.addition(mchntSettleAmt, comfirmMchntOrderInfo.getMchntSettleAmt());
                mchntFee = AmountUtil.addition(mchntFee, comfirmMchntOrderInfo.getMchntFee());
                realMchntFee = AmountUtil.addition(realMchntFee, comfirmMchntOrderInfo.getRealMchntFee());
            }
        }
        rglog.debug("已经确认收货的金额:<{}>", comfirmedMchntOrderAmt);
        rglog.debug("已经确认收货对客免充值的金额:<{}>", comfirmCtomerMarketAmt);
        rglog.debug("已完成确认收货的清算本金金额:<{}>", realSettleAmt);
        rglog.debug("已完成确认收货的商户结算金额:<{}>", mchntSettleAmt);
        rglog.debug("已完成确认收货的商户应收手续费:<{}>", mchntFee);
        rglog.debug("已完成确认收货的商户实收手续费:<{}>", realMchntFee);

        /* Step1.2：获取当前商户订单已退款的金额 */
        String refundMchntOrderAmt = "0.00";
        String refundCtomerMarketAmt = "0.00";
        String refundRealSettleAmt = "0.00";
        String refundMchntSettleAmt = "0.00";
        String refundTotalFee = "0.00";
        String refundRealMchntFee = "0.00";
        if (refundOrComfirmMchntOrderInfos != null && !refundOrComfirmMchntOrderInfos.isEmpty()) {
            List<MchntOrderInfo> refundMchntOrderList = refundOrComfirmMchntOrderInfos.stream().filter(item -> item.getMchntNo().equals(mchntNo) &&
                    TransTypeEnum.REFUND.equals(TransTypeEnum.getTransType(item.getTxnNum()))).collect(Collectors.toList());
            for (MchntOrderInfo refundMchntOrderInfo : refundMchntOrderList) {
                /* Step1.2.1 条件判断:交易状态为成功或则超时 业务状态为未确认收货全额退款或未确认收货部分退款或业务处理中的退款交易 */
                if (TransStatusEnum.TRANS_SUCC.getStatus().equals(refundMchntOrderInfo.getTransStatus())
                        || TransStatusEnum.TRANS_TIMEOUT.getStatus().equals(refundMchntOrderInfo.getTransStatus())) {
                    if (BizStatusEnum.NOT_CONFIRM_REFUND.getStatus().equals(refundMchntOrderInfo.getBizStatus())
                            || BizStatusEnum.NOT_CONFIRM_PART_REFUND.getStatus().equals(refundMchntOrderInfo.getBizStatus())
                            || BizStatusEnum.PROCESSING.getStatus().equals(refundMchntOrderInfo.getBizStatus())) {
                        refundMchntOrderAmt = AmountUtil.addition(refundMchntOrderAmt, refundMchntOrderInfo.getOrderAmt());
                        refundCtomerMarketAmt = AmountUtil.addition(refundCtomerMarketAmt, refundMchntOrderInfo.getCustomerMarketAmt());
                        refundRealSettleAmt = AmountUtil.addition(refundRealSettleAmt, refundMchntOrderInfo.getRealSettleAmt());
                        refundMchntSettleAmt = AmountUtil.addition(refundMchntSettleAmt, refundMchntOrderInfo.getMchntSettleAmt());
                        refundTotalFee = AmountUtil.addition(refundTotalFee, refundMchntOrderInfo.getMchntFee());
                        refundRealMchntFee = AmountUtil.addition(refundRealMchntFee, refundMchntOrderInfo.getRealMchntFee());
                    }
                }
            }
        }
        rglog.debug("已退款的交易金额:<{}>", refundMchntOrderAmt);
        rglog.debug("已退货对客免充值的金额:<{}>", refundCtomerMarketAmt);
        rglog.debug("已退款的清算本金金额:<{}>", refundRealSettleAmt);
        rglog.debug("已退款的商户结算金额:<{}>", refundMchntSettleAmt);
        rglog.debug("已退款的商户应收手续费:<{}>", refundTotalFee);
        rglog.debug("已退款的商户实收手续费:<{}>", refundRealMchntFee);

        /* Step2：当前总共确认的金额 */
        String totalComfirmAmt = AmountUtil.addition(comfirmedMchntOrderAmt, payConfirmRequest.getOrderAmt());
        rglog.debug("当前总确认收货金额:<{}>", totalComfirmAmt);
        totalComfirmAmt = AmountUtil.addition(totalComfirmAmt, refundMchntOrderAmt);
        rglog.debug("当前累计确认+已退款的金额:<{}>", totalComfirmAmt);

        /*
         * 获取当前确认收货的金额与商户订单金额的比例
         * 非最后一次确认收货的交易 确认收货的商户订单涉及金额按照比例计算
         * 最后一次确认收货的交易 确认收货的商户订单使用原商户订单表中的数据减去已发生确认收货商户订单之和
         */
        if (AmountUtil.compare(mchntOrderInfo.getOrderAmt(), totalComfirmAmt) == -1) {
            rglog.info("总确认金额:<{}>大于商户订单的订单金额:<{}>", totalComfirmAmt, mchntOrderInfo.getOrderAmt());
            throw new BizException(RespCodeEnum.OPM_OVER_AMT_LIMIT.getRespCode(), RespCodeEnum.OPM_OVER_AMT_LIMIT.getRespDesc());
        } else if (AmountUtil.compare(mchntOrderInfo.getOrderAmt(), totalComfirmAmt) == 1) {
            /* Step2.1：当前确认收货的金额所占商户订单订单的比例 */
            String rate = AmountUtil.division(payConfirmRequest.getOrderAmt(), mchntOrderInfo.getOrderAmt(), 3);
            rglog.debug("当前确认收货的金额所占商户订单订单的比例:<{}>", rate);
            /* Step2.2：当计算确认收货的商户清算本金=订单结算金额总值-(确认收货订单金额*对客免充值金额)/订单总金额 */
            String orderSettleAmt = xmlTreeUtil.getXmlTreeStringValue("orderSettleAmt");
            String customerMarketAmt = AmountUtil.division(AmountUtil.multiplication(mchntOrderInfo.getCustomerMarketAmt(), payConfirmRequest.getOrderAmt()), mchntOrderInfo.getOrderAmt(), 2);
            rglog.debug("当前确认收货金额计算得到其免充值营销金额:<{}>", customerMarketAmt);
            MchntOrderInfo mchntOrderInfooRedeem = new MchntOrderInfo();
            BeanUtil.beanCopy(mchntOrderInfo, mchntOrderInfooRedeem);
            mchntOrderInfooRedeem.setOrderAmt(payConfirmRequest.getOrderAmt());
            mchntOrderInfooRedeem.setCustomerMarketAmt(customerMarketAmt);
            mchntOrderInfooRedeem.setRedeemCouponIds((String) GlobalTransUtil.getCacheValue(TransCacheConstant.COUPON_ID_LIST));
            mchntOrderInfooRedeem.setOrderDiscountAmt(xmlTreeUtil.getXmlTreeStringValue("orderDiscountAmt"));
            mchntOrderInfooRedeem.setRealSettleAmt(AmountUtil.subtraction(orderSettleAmt, customerMarketAmt));
            mchntOrderInfooRedeem.setMchntFee(AmountUtil.division(AmountUtil.multiplication(payConfirmRequest.getOrderAmt(), mchntOrderInfo.getMchntFee()), mchntOrderInfo.getOrderAmt(), 2));
            mchntOrderInfooRedeem.setRealMchntFee(AmountUtil.division(AmountUtil.multiplication(payConfirmRequest.getOrderAmt(), mchntOrderInfo.getRealMchntFee()), mchntOrderInfo.getOrderAmt(), 2));
            mchntOrderInfooRedeem.setMchntDiscountFee(AmountUtil.subtraction(mchntOrderInfooRedeem.getMchntFee(), mchntOrderInfooRedeem.getRealMchntFee()));
            mchntOrderInfooRedeem.setMchntSettleAmt(AmountUtil.subtraction(mchntOrderInfooRedeem.getRealSettleAmt(), mchntOrderInfooRedeem.getRealMchntFee()));
            mchntOrderInfooRedeem.setTxnDate(xmlTreeUtil.getXmlTreeStringValue(TreeNodeConstant.TXN_DATE));
            mchntOrderInfooRedeem.setTxnTime(xmlTreeUtil.getXmlTreeStringValue(TreeNodeConstant.TXN_TIME));
            mchntOrderInfooRedeem.setSysSeqNum(xmlTreeUtil.getXmlTreeStringValue(TreeNodeConstant.SYS_SEQ_NUM));
            mchntOrderInfooRedeem.setTransStatus(TransStatusEnum.TRANS_SUCC.getStatus());
            mchntOrderInfooRedeem.setBizStatus(BizStatusEnum.FINISH.getStatus());
            mchntOrderInfooRedeem.setCreateTime(DateUtil.getCurrentDateTime("yyyy-MM-dd HH:mm:ss.SSS"));
            mchntOrderInfooRedeem.setOrigSysSeqNum(mchntOrderInfo.getSysSeqNum());
            mchntOrderInfooRedeem.setOrigTxnDate(mchntOrderInfo.getTxnDate());
            mchntOrderInfooRedeem.setTxnNum(payConfirmRequest.getHeader().getTxnNum());
            mchntOrderInfooRedeem.setMchntOrderId(payConfirmRequest.getConfirmOrderDetailList().get(0).getMchntSubOrderId());
            mchntOrderInfooRedeem.setMchntNo(payConfirmRequest.getConfirmOrderDetailList().get(0).getMchntNo());
            mchntOrderInfooRedeem.setBizSceneType(mchntOrderInfo.getBizSceneType());
            return mchntOrderInfooRedeem;
        } else {
            rglog.debug("最后一笔确认收货的商户订单，使用原商户订单手续费减去已发生确认收货的手续费");
            realSettleAmt = AmountUtil.addition(realSettleAmt, refundRealSettleAmt);
            mchntFee = AmountUtil.addition(mchntFee, refundTotalFee);
            realMchntFee = AmountUtil.addition(realMchntFee, refundRealMchntFee);
            String totalCtomerMarketAmt = AmountUtil.addition(comfirmCtomerMarketAmt, refundCtomerMarketAmt);
            rglog.debug("已确认+已退款的商户清算本金:<{}>", realSettleAmt);
            rglog.debug("已确认+已退款的商户手续费:<{}>", mchntFee);
            rglog.debug("已确认+已退款的商户实收手续费:<{}>", realMchntFee);
            rglog.debug("已确认+已退款的商户对客免充值金额:<{}>", totalCtomerMarketAmt);
            MchntOrderInfo mchntOrderInfooRedeem = new MchntOrderInfo();
            BeanUtil.beanCopy(mchntOrderInfo, mchntOrderInfooRedeem);
            mchntOrderInfooRedeem.setOrderAmt(payConfirmRequest.getOrderAmt());
            mchntOrderInfooRedeem.setCustomerMarketAmt(AmountUtil.subtraction(mchntOrderInfo.getCustomerMarketAmt(), totalCtomerMarketAmt));
            mchntOrderInfooRedeem.setRedeemCouponIds((String) GlobalTransUtil.getCacheValue(TransCacheConstant.COUPON_ID_LIST));
            mchntOrderInfooRedeem.setOrderDiscountAmt(xmlTreeUtil.getXmlTreeStringValue("orderDiscountAmt"));
            mchntOrderInfooRedeem.setRealSettleAmt(AmountUtil.subtraction(mchntOrderInfo.getRealSettleAmt(), realSettleAmt));
            mchntOrderInfooRedeem.setMchntFee(AmountUtil.subtraction(mchntOrderInfo.getMchntFee(), mchntFee));
            mchntOrderInfooRedeem.setRealMchntFee(AmountUtil.subtraction(mchntOrderInfo.getRealMchntFee(), realMchntFee));
            mchntOrderInfooRedeem.setMchntSettleAmt(AmountUtil.subtraction(mchntOrderInfooRedeem.getRealSettleAmt(), mchntOrderInfooRedeem.getRealMchntFee()));
            mchntOrderInfooRedeem.setMchntDiscountFee(AmountUtil.subtraction(mchntOrderInfooRedeem.getMchntFee(), mchntOrderInfooRedeem.getRealMchntFee()));
            mchntOrderInfooRedeem.setTxnDate(xmlTreeUtil.getXmlTreeStringValue(TreeNodeConstant.TXN_DATE));
            mchntOrderInfooRedeem.setTxnTime(xmlTreeUtil.getXmlTreeStringValue(TreeNodeConstant.TXN_TIME));
            mchntOrderInfooRedeem.setSysSeqNum(xmlTreeUtil.getXmlTreeStringValue(TreeNodeConstant.SYS_SEQ_NUM));
            mchntOrderInfooRedeem.setTransStatus(TransStatusEnum.TRANS_SUCC.getStatus());
            mchntOrderInfooRedeem.setBizStatus(BizStatusEnum.FINISH.getStatus());
            mchntOrderInfooRedeem.setCreateTime(DateUtil.getCurrentDateTime("yyyy-MM-dd HH:mm:ss.SSS"));
            mchntOrderInfooRedeem.setOrigSysSeqNum(mchntOrderInfo.getSysSeqNum());
            mchntOrderInfooRedeem.setOrigTxnDate(mchntOrderInfo.getTxnDate());
            mchntOrderInfooRedeem.setTxnNum(payConfirmRequest.getHeader().getTxnNum());
            mchntOrderInfooRedeem.setMchntOrderId(payConfirmRequest.getConfirmOrderDetailList().get(0).getMchntSubOrderId());
            mchntOrderInfooRedeem.setMchntNo(payConfirmRequest.getConfirmOrderDetailList().get(0).getMchntNo());
            mchntOrderInfooRedeem.setBizSceneType(mchntOrderInfo.getBizSceneType());
            return mchntOrderInfooRedeem;
        }
    }

    /**
     * 更新商户订单明细列表
     *
     * @param payConfirmRequest 担保支付请求
     * @param mchntOrderInfo    商户订单
     * @throws Exception 异常
     */
    private void updateMchntOrderDetails(PayConfirmRequest payConfirmRequest, MchntOrderInfo mchntOrderInfo) throws Exception {
        OrderService orderService = new OrderServiceImpl();
        List<MchntOrderDetail> mchntDetailOrderList = (List<MchntOrderDetail>) GlobalTransUtil.getCacheValue(TransCacheConstant.MCHNT_ORDER_DETAIL_LIST);
        if (null != mchntDetailOrderList && !mchntDetailOrderList.isEmpty()) {
            for (OrderDetail orderDetail : payConfirmRequest.getConfirmOrderDetailList()) {
                //获取担保支付确认对应的商户子订单信息
                Optional<MchntOrderDetail> mchntOrderDetailOptional = mchntDetailOrderList.stream().filter(item -> item.getMchntSubOrderId().equals(orderDetail.getMchntSubOrderId())).findFirst();
                if (mchntOrderDetailOptional.isPresent()) {
                    MchntOrderDetail mchntOrderDetail = mchntOrderDetailOptional.get();
                    //计算当前子订单确认收货金额占整个商户订单金额比例
                    String rate = AmountUtil.division(orderDetail.getOrderAmt(), mchntOrderInfo.getOrderAmt(), 2);
                    rglog.debug("商户子订单金额占整个商户订单的比率为:<{}>", rate);
                    mchntOrderDetail.setMchntFee(AmountUtil.multiplication(rate, mchntOrderInfo.getMchntFee(), 2));
                    mchntOrderDetail.setRealMchntFee(AmountUtil.multiplication(rate, mchntOrderInfo.getRealMchntFee(), 2));
                    mchntOrderDetail.setMchntDiscountFee(AmountUtil.subtraction(mchntOrderDetail.getMchntFee(), mchntOrderDetail.getRealMchntFee()));
                    mchntOrderDetail.setMchntOrderStatus("00");
                }
            }
            if (!orderService.updateOrderInfo(null, null, mchntDetailOrderList, null)) {
                rglog.info("更新商户子订单失败");
                throw new BizException(RespCodeEnum.UPDATE_ORDER_ERROR.getRespCode(), RespCodeEnum.UPDATE_ORDER_ERROR.getRespDesc());
            }
        }
    }

    /**
     * 转换计算手续费时的手续费类型
     *
     * @param payOrderInfo 支付订单
     * @return 手续费类型
     */
    String convFeeType(PayOrderInfo payOrderInfo) {
        if (PayTypeEnum.BANK_CARD.getPayType().equals(payOrderInfo.getPayType())) {
            if (AcctTypeEnum.BANK_DEBIT.getAcctType().equals(payOrderInfo.getPayerAcctType())) {
                return FeeTypeEnum.BANK_DR_CARD.getFeeType();
            } else {
                return FeeTypeEnum.OTHER_BANK_DR_CARD.getFeeType();
            }
        } else if (PayTypeEnum.OTHER_BANK_CARD.getPayType().equals(payOrderInfo.getPayType())) {
            if (AcctTypeEnum.OTHER_DEBIT.getAcctType().equals(payOrderInfo.getPayerAcctType())) {
                return FeeTypeEnum.OTHER_BANK_DR_CARD.getFeeType();
            } else {
                return FeeTypeEnum.OTHER_BANK_CR_CARD.getFeeType();
            }
        } else if (PayTypeEnum.WECHAT.getPayType().equals(payOrderInfo.getPayType())) {
            return FeeTypeEnum.WECHAT.getFeeType();
        } else if (PayTypeEnum.ALIPAY.getPayType().equals(payOrderInfo.getPayType())) {
            return FeeTypeEnum.ALIPAY.getFeeType();
        } else if (PayTypeEnum.CUPS_CLOUD.getPayType().equals(payOrderInfo.getPayType())) {
            if (AcctTypeEnum.OTHER_DEBIT.getAcctType().equals(payOrderInfo.getPayerAcctType())) {
                return FeeTypeEnum.UPQR_DR.getFeeType();
            } else {
                return FeeTypeEnum.UPQR_CR.getFeeType();
            }
        } else {
            rglog.error("未知支付类型<{}>", payOrderInfo.getPayType());
            return null;
        }
    }
}
